package com.byb.server.service.impl;

import com.byb.server.domain.Product;
import com.byb.server.repository.ProductRepository;
import com.byb.server.repository.search.ProductSearchRepository;
import com.byb.server.service.RateService;
import com.byb.server.domain.Rate;
import com.byb.server.repository.RateRepository;
import com.byb.server.repository.search.RateSearchRepository;
import com.byb.server.service.dto.Product_sort;
import com.byb.server.service.dto.RateDTO;
import com.byb.server.service.mapper.Product_sortMapper;
import com.byb.server.service.mapper.RateMapper;
import com.byb.server.service.util.AgeUtil;
import com.byb.server.service.util.RankProduct;
import com.byb.server.service.util.SexUtil;
import com.byb.server.service.util.StrategyFactory;
import com.byb.server.service.util.rebuild.SortStyService;
import com.byb.server.service.util.rebuild.StrategyRebuild;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * Service Implementation for managing Rate.
 */
@Service
@Transactional
public class RateServiceImpl implements RateService {

    private final Logger log = LoggerFactory.getLogger(RateServiceImpl.class);

    private final RateRepository rateRepository;

    private final ProductSearchRepository productSearchRepository;

    private final RateMapper rateMapper;

    private final Product_sortMapper productSortMapper;

    private final RateSearchRepository rateSearchRepository;

    private final ProductRepository productRepository;

    @Qualifier("sortScore")
    private final SortStyService sortScore;

    @Qualifier("sortMoney")
    private final  SortStyService sortMoney;

    @Qualifier("sortProtectScore")
    private final SortStyService sortProtectScore;

    public RateServiceImpl(RateRepository rateRepository, RateMapper rateMapper, Product_sortMapper productSortMapper, RateSearchRepository rateSearchRepository, ProductSearchRepository productSearchRepository, ProductRepository productRepository, SortStyService sortScore, SortStyService sortMoney, SortStyService sortProtectScore) {
        this.rateRepository = rateRepository;
        this.rateMapper = rateMapper;
        this.productSortMapper = productSortMapper;
        this.rateSearchRepository = rateSearchRepository;
        this.productSearchRepository = productSearchRepository;
        this.productRepository = productRepository;
        this.sortScore = sortScore;
        this.sortMoney = sortMoney;
        this.sortProtectScore = sortProtectScore;
    }

    /**
     * Save a rate.
     *
     * @param rateDTO the entity to save
     * @return the persisted entity
     */
    @Override
    public RateDTO save(RateDTO rateDTO) {
        log.debug("Request to save Rate : {}", rateDTO);
        Rate rate = rateMapper.toEntity(rateDTO);
        rate = rateRepository.save(rate);
        RateDTO result = rateMapper.toDto(rate);
        //rateSearchRepository.save(rate);
        return result;
    }

    /**
     * Get all the rates.
     *
     * @param pageable the pagination information
     * @return the list of entities
     */
    @Override
    @Transactional(readOnly = true)
    public Page<RateDTO> findAll(Pageable pageable) {
        log.debug("Request to get all Rates");
        return rateRepository.findAll(pageable)
            .map(rateMapper::toDto);
    }

    /**
     * Get one rate by id.
     *
     * @param id the id of the entity
     * @return the entity
     */
    @Override
    @Transactional(readOnly = true)
    public RateDTO findOne(Long id) {
        log.debug("Request to get Rate : {}", id);
        Rate rate = rateRepository.findOne(id);
        return rateMapper.toDto(rate);
    }

    /**
     * Delete the  rate by id.
     *
     * @param id the id of the entity
     */
    @Override
    public void delete(Long id) {
        log.debug("Request to delete Rate : {}", id);
        rateRepository.delete(id);
        //rateSearchRepository.delete(id);
    }

    /**
     * Search for the rate corresponding to the query.
     *
     * @param query    the query of the search
     * @param pageable the pagination information
     * @return the list of entities
     */
    @Override
    @Transactional(readOnly = true)
    public Page<RateDTO> search(String query, Pageable pageable) {
        log.debug("Request to search for a page of Rates for query {}", query);
        Page<Rate> result = rateSearchRepository.search(queryStringQuery(query), pageable);
        return result.map(rateMapper::toDto);
    }


    /**
     * Get all the Product for sort.
     *
     * @param ageDate
     * @param premiumPaymentPeriod
     * @param sexName
     * @param pageable             the pagination information
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Product_sort> sort(String ageDate, Integer premiumPaymentPeriod, String sexName, Pageable pageable) {
        log.debug("Request to get all Rates for sort");
        return rateRepository.findByAgeAndPremiumPaymentPeriodAndSexSexName(AgeUtil.getAge(ageDate), premiumPaymentPeriod, sexName, pageable).map(productSortMapper::toDto);
    }

    /**
     * Calculate list according to payment  -- 根据sort() 的数据，进行保费的计算
     *
     * @param orderByState
     * @param list
     * @param payment
     * @param query
     * @param pageable     the pagination information
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List<Product_sort> sortByState(Integer orderByState, List<Product_sort> list, Integer payment, Collection<Long> query, Pageable pageable) {
        //获取关键词 数据
        List<Product> products = null;
        if (query != null) {
            products = productRepository.findAllByWordKeysIsIn(query, query.size(), pageable).getContent();
        }
        List<Product> data = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            data.add(productRepository.findOne(list.get(i).getProductId()));
        }
        //根据 product 过滤数据，并计算保费
        return RankProduct.getContext(StrategyFactory.getSortStrategy(orderByState)).ranking(list, products, data, payment);
    }

    @Override
    public List<Product_sort> sortRank(String age, Integer premiumPaymentPeriod, String sexName, Integer payment, Integer orderByState, String query, Pageable pageable) {

        Rate rates = rateRepository.findAllByAgeAndPremiumPaymentPeriodAndSexAndAgeAfter(AgeUtil.getAge(age), premiumPaymentPeriod, SexUtil.getSex_id(sexName));
        Product_sort product_sort01 = productSortMapper.toDto(rates);
        Gson gson = new Gson();
        switch (orderByState) {
            case 0: {
              return   StrategyRebuild.getContext(sortScore).getProduct(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                    gson.fromJson(query, new TypeToken<Collection<Long>>() {
                    }.getType()), product_sort01, pageable);
            }
            case 1: {
             return    StrategyRebuild.getContext(sortMoney).getProduct(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                    gson.fromJson(query, new TypeToken<Collection<Long>>() {
                    }.getType()), product_sort01, pageable);
            }
            case 2: {
              return   StrategyRebuild.getContext(sortProtectScore).getProduct(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                    gson.fromJson(query, new TypeToken<Collection<Long>>() {
                    }.getType()), product_sort01, pageable);
            }
        }
        return null;
    }

    /**
     * 批量上传数据Rate
     *
     * @param list
     * @return
     */
    @Override
    public boolean saves(List<RateDTO> list) {
        log.debug("Request to save Rate : {}", list);
        List<Rate> data = list.stream().map(rateMapper::toEntity).collect(Collectors.toList());
        rateRepository.save(data);
        //rateSearchRepository.save(data);
        return true;

    }
}
